package server;

import com.github.wenzi.servlet.HttpServlet;
import com.github.wenzi.servlet.HttpServletWapper;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;

import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Minicat的主类
 */
public class Bootstrap {

    /**定义socket监听的端口号*/
    private int port = 8080;

    //连接器组件
    private Connect connect;
    //mapper组件
    private Mapper mapper;

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }




    /**
     * Minicat启动需要初始化展开的一些操作
     */
    public void start() throws Exception {
        startConnect();



    }

    /**
     * 启动连接器监听
     */
    private void startConnect() {
        this.connect.start();
    }

    //加载server.xml配置文件
    private void init() {

        try{
            //初始化连接器组件
            initMapper();
            //初始化连接器组件
            initConnect();

        }catch (Exception e){
            e.printStackTrace();
        }

    }

    private void initMapper() throws DocumentException, FileNotFoundException {
        this.mapper=new Mapper();

        InputStream stream = this.getClass().getClassLoader().getResourceAsStream("server.xml");
        SAXReader saxReader=new SAXReader();
        Document document = saxReader.read(stream);
        Element rootElement = document.getRootElement();
        List<Element> hostListNode = rootElement.selectNodes("//Host");
        for (Element element : hostListNode) {
            String name = element.attributeValue("name");
            String appBase = element.attributeValue("appBase");

            Element contentNode = (Element) element.selectSingleNode("Context");
            String docBase = contentNode.attributeValue("docBase");
            String path = contentNode.attributeValue("path");

            Map<String, HttpServletWapper> servletWapperMap=buildServletMap(appBase,docBase,path);
            Content content=new Content(docBase,path,servletWapperMap);

            Host host=new Host(name,appBase,content);
            this.mapper.addHost(host);

        }
    }

    private Map<String, HttpServletWapper> buildServletMap(String appBase, String docBase, String contentPath) throws FileNotFoundException, DocumentException {
        Map<String, HttpServletWapper> servletWapperMap=new HashMap<>();
        String path=appBase+"/"+docBase;
        File file=new File(path);
        if(file.exists()&&file.isDirectory()){

            File subFile=new File(file,"WEB-INF/web.xml");
            if(subFile.exists()&&subFile.isFile()){
                FileInputStream stream = new FileInputStream(subFile);
                servletWapperMap = loadServlet(stream, contentPath,path);
            }
        }
        return servletWapperMap;
    }

    /**
     * 初始化连接器组件
     */
    private void initConnect() throws DocumentException, IOException {
        //解析server
        InputStream stream = this.getClass().getClassLoader().getResourceAsStream("server.xml");
        SAXReader saxReader=new SAXReader();
        Document document = saxReader.read(stream);
        Element rootElement = document.getRootElement();
        Element connectorNode = (Element) rootElement.selectSingleNode("//Connector");
        String port = connectorNode.attributeValue("port");
        this.connect=new Connect(Integer.valueOf(port),mapper);

    }


    /**
     * 加载解析web.xml，初始化Servlet
     */
    private Map<String,HttpServletWapper> loadServlet(FileInputStream inputStream,String contentPath,String path) {
        Map<String,HttpServletWapper> servletWapperMap=new HashMap<>();
        SAXReader saxReader = new SAXReader();
        try {
            Document document = saxReader.read(inputStream);
            Element rootElement = document.getRootElement();

            List<Node> selectNodes = rootElement.selectNodes("//servlet");
            for (int i = 0; i < selectNodes.size(); i++) {
                Element element = (Element) selectNodes.get(i);
                // <servlet-name>lagou</servlet-name>
                Element servletnameElement = (Element) element.selectSingleNode("servlet-name");
                String servletName = servletnameElement.getStringValue();
                // <servlet-class>server.LagouServlet</servlet-class>
                Element servletclassElement = (Element) element.selectSingleNode("servlet-class");
                String servletClass = servletclassElement.getStringValue();

                // 根据servlet-name的值找到url-pattern
                Element servletMapping = (Element) rootElement.selectSingleNode("/web-app/servlet-mapping[servlet-name='" + servletName + "']");
                // /lagou
                String urlPattern = contentPath+servletMapping.selectSingleNode("url-pattern").getStringValue();
                URL url = new File(path+"/WEB-INF/classes").toURL();
                URLClassLoader classLoader=new URLClassLoader(new URL[]{url});
                Class<?> serveltClass = classLoader.loadClass(servletClass);
                HttpServlet httpServlet = (HttpServlet) serveltClass.newInstance();;
                HttpServletWapper servletWapper = new HttpServletWapper(httpServlet);
                servletWapperMap.put(urlPattern, servletWapper);

            }


        } catch (DocumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
        return servletWapperMap;

    }


    /**
     * Minicat 的程序启动入口
     * @param args
     */
    public static void main(String[] args) {
        Bootstrap bootstrap = new Bootstrap();
        bootstrap.init();
        try {
            // 启动Minicat
            bootstrap.start();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
